package main

import (
	"bytes"
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
	"net/http"
	"strconv"
	"sync"
	"time"
)

type testResult struct {
	tps int
	rt  time.Duration
}

type Reader interface {
	Read(p []byte) (n int, err error)
}

func main() {
	a := app.New()
	w := a.NewWindow("HTTP Load Testing Tool")
	urlEntry := widget.NewEntry()
	urlEntry.SetPlaceHolder("Enter URL")
	reqBodyEntry := widget.NewEntry()
	reqBodyEntry.SetPlaceHolder("Enter Request Body")
	reqHeaderEntry := widget.NewEntry()
	reqHeaderEntry.SetPlaceHolder("Enter Request Header")
	reqCountEntry := widget.NewEntry()
	reqCountEntry.SetPlaceHolder("Enter Request Count")
	concurrencyEntry := widget.NewEntry()
	concurrencyEntry.SetPlaceHolder("Enter Concurrency")
	//durationEntry := widget.NewEntry()
	//durationEntry.SetPlaceHolder("Enter Duration in Seconds")
	methodSelector := widget.NewSelect([]string{"GET", "POST", "PUT", "DELETE"}, func(s string) {})
	methodSelector.SetSelected("GET")
	startButton := widget.NewButton("Start", func() {
		url := urlEntry.Text
		reqBody := reqBodyEntry.Text
		reqHeader := reqHeaderEntry.Text
		reqCount, _ := strconv.Atoi(reqCountEntry.Text)
		concurrency, _ := strconv.Atoi(concurrencyEntry.Text)
		//duration, _ := strconv.ParseInt(durationEntry.Text, 10, 64)
		method := methodSelector.Selected
		var wg sync.WaitGroup
		resultChan := make(chan testResult)
		start := time.Now()
		for i := 0; i < concurrency; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				for j := 0; j < reqCount/concurrency; j++ {
					startReq := time.Now()
					client := &http.Client{}
					var req *http.Request
					var err error
					switch method {
					case "GET":
						req, err = http.NewRequest("GET", url, nil)
					case "POST":
						req, err = http.NewRequest("POST", url, bytes.NewBuffer([]byte(reqBody)))
					case "PUT":
						req, err = http.NewRequest("PUT", url, bytes.NewBuffer([]byte(reqBody)))
					case "DELETE":
						req, err = http.NewRequest("DELETE", url, nil)
					default:
						panic("Invalid HTTP method")
					}
					if reqHeader != "" {
						header := http.Header{}
						header.Add("Content-Type", "application/json")
						req.Header = header
					}
					resp, err := client.Do(req)
					if err != nil {
						fmt.Println(err)
						continue
					}
					defer resp.Body.Close()
					elapsed := time.Since(startReq)
					resultChan <- testResult{tps: 1, rt: elapsed}
				}
			}()
		}
		go func() {
			wg.Wait()
			close(resultChan)
		}()
		var totalTps int
		var totalRt time.Duration
		var count int
		for result := range resultChan {
			totalTps += result.tps
			totalRt += result.rt
			count++
			if count == reqCount {
				break
			}
		}
		elapsed := time.Since(start)
		tps := float64(totalTps) / elapsed.Seconds()
		avgRt := totalRt / time.Duration(count)
		fmt.Printf("%f", elapsed.Seconds())
		//go func() {
		//	if float64(duration) == elapsed.Seconds() {
		//		wg.Wait()
		//		close(resultChan)
		//		fmt.Printf("TPS: %.2f\n", tps)
		//		fmt.Printf("Avg RT: %v\n", avgRt)
		//		w.Close()
		//	}
		//}()
		stopButton := widget.NewButton("Stop", func() {
			fmt.Printf("TPS: %.2f\n", tps)
			fmt.Printf("Avg RT: %v\n", avgRt)
			w.Close()
		})
		w.SetContent(container.NewVBox(
			widget.NewLabel("Testing in progress..."),
			stopButton,
		))
	})
	form := &widget.Form{
		Items: []*widget.FormItem{
			{Text: "URL", Widget: urlEntry},
			{Text: "Request Body", Widget: reqBodyEntry},
			{Text: "Request Header", Widget: reqHeaderEntry},
			{Text: "Request Count", Widget: reqCountEntry},
			{Text: "Concurrency", Widget: concurrencyEntry},
			//{Text: "Duration", Widget: durationEntry},
			{Text: "HTTP Method", Widget: methodSelector},
		},
	}
	w.SetContent(container.NewVBox(
		form,
		startButton,
	))
	w.Resize(fyne.NewSize(400, 400))
	w.ShowAndRun()
}
